﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
namespace WHLRDF.ORM
{
    public class CustomModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Metadata.ModelType != null && context.Metadata.MetadataKind == ModelMetadataKind.Parameter && context.Metadata.ModelType.BaseType == typeof(EntityBase))
            {
                return new BinderTypeModelBinder(typeof(CustomModelBinder));
            }

            return null;
        }


    }
    public class CustomModelBinder : IModelBinder
    {


        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
            object model = ReflectionHelper.CreateInstance(bindingContext.ModelMetadata.ModelType);
            var dbEntity = model as EntityBase;
            string strError = "";
            DataProxy dataProxy = new DataProxy(bindingContext.ModelMetadata.ModelType);
            var PrimaryValueResult = bindingContext.ValueProvider.GetValue(dataProxy.PrimaryKeyName);
            if (PrimaryValueResult == ValueProviderResult.None)
            {
                PrimaryValueResult = bindingContext.ValueProvider.GetValue("id");
            }
            if (PrimaryValueResult != ValueProviderResult.None && !string.IsNullOrWhiteSpace(PrimaryValueResult.FirstValue))
            {
                ICriterion criterion = Expression.Eq(dataProxy.PrimaryKeyName, PrimaryValueResult.FirstValue);
                dbEntity.Retrieve(dataProxy, criterion);
            }
            if (model != null)
            {
                foreach (var item in dataProxy.EntityFields.Where(x => x.CanWrite))
                {
                    var fieldValue = bindingContext.ValueProvider.GetValue(item.Name);

                    Type fieldtype = Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType;
                    if (AppHttpContext.IsPost)//表单提交时验证提交内容
                    {
                        if (fieldValue != ValueProviderResult.None || dbEntity.State == EntityState.Add)
                        {
                            var dbColumn = dataProxy.DbFields.Where(x => x.Name.Equals(item.Name)).FirstOrDefault();
                            if (dbColumn != null && dbColumn.IsSystem)//系统字段不赋值 也不验证
                            {
                                continue;
                            }
                            if (dbColumn != null && !dbColumn.IsPrimaryKey)
                            {
                                if (!CheckValidHelper.CheckInput(dbColumn.LocalName, dbColumn.AllowDBNull, string.IsNullOrWhiteSpace(dbColumn.VaildKey) ? "" : dbColumn.VaildKey, true,
                              (fieldValue != null ? fieldValue.ToString().Trim() : ""), 0, dbColumn.MaxLength, dbColumn.Min, dbColumn.Max, dbColumn.RegValidate, ref strError, dbColumn.ColumnType))
                                {
                                    bindingContext.ModelState.AddModelError(item.Name, strError);
                                }
                                if (string.IsNullOrWhiteSpace(fieldValue.ToString().Trim()) && !string.IsNullOrWhiteSpace(dbColumn.Default))
                                {
                                    item.SetValue(model, Convert.ChangeType(dbColumn.Default.ToString().Trim(), fieldtype));
                                }
                            }
                        }
                    }
                    if (fieldValue != ValueProviderResult.None)
                    {
                        if (string.IsNullOrWhiteSpace(fieldValue.ToString().Trim()))
                        {
                            if (item.PropertyType.Name == nameof(System.String))
                            {
                                item.SetValue(model, "");
                            }
                            else if (CheckValidHelper.IsNullableType(item.PropertyType))
                            {
                                item.SetValue(model, null);
                            }
                        }
                        else
                        {
                            var value = Convert.ChangeType(fieldValue.FirstValue.ToString().Trim(), fieldtype);
                            item.SetValue(model, value);
                        }
                    }

                }
            }
            bindingContext.Result = ModelBindingResult.Success(model);
            return Task.CompletedTask;
        }
    }

}
